#ifndef __U2GLESFBO_H__
#define __U2GLESFBO_H__


#include "U2GLESPreRequest.h"
#include "U2GLESRenderTexture.h"
#include "U2GLESContext.h"


U2EG_NAMESPACE_BEGIN


class GLESFBOManager;
struct U2GLESSurfaceDesc;

/** Frame Buffer Object abstraction.
*/
class _U2GLESShare GLESFrameBufferObject
{
public:
    GLESFrameBufferObject(GLESFBOManager *manager, u2uint fsaa);
    ~GLESFrameBufferObject();

    /** Bind a surface to a certain attachment point.
        attachment: 0..U2_MAX_MULTIPLE_RENDER_TARGETS-1
    */
    void bindSurface(size_t attachment, const U2GLESSurfaceDesc &target);

    /** Unbind attachment
    */
    void unbindSurface(size_t attachment);
    
    /** Bind FrameBufferObject
    */
    void bind();

	/** Swap buffers - only useful when using multisample buffers.
	*/
	void swapBuffers();

    /** This function acts very similar to @see GLESFBORenderTexture::attachDepthBuffer
		The difference between D3D & OGL is that D3D setups the U2DepthBuffer before rendering,
		while OGL setups the U2DepthBuffer per FBO. So the U2DepthBuffer (RenderBuffer) needs to
		be attached for OGL.
	*/
	void attachDepthBuffer( U2DepthBuffer *depthBuffer );
	void detachDepthBuffer();

    /// Accessors
    size_t getWidth();
    size_t getHeight();
    PixelFormat getFormat();
	GLsizei getFSAA();

    GLESFBOManager *getManager() { return mManager; }
	const U2GLESSurfaceDesc &getSurface(size_t attachment) { return mColour[attachment]; }

private:

    GLESFBOManager *mManager;
	GLsizei mNumSamples;
    GLuint mFB;
	GLuint mMultisampleFB;
	U2GLESSurfaceDesc mMultisampleColourBuffer;
    U2GLESSurfaceDesc mDepth;
    U2GLESSurfaceDesc mStencil;
    // Arbitrary number of texture surfaces
    U2GLESSurfaceDesc mColour[U2_MAX_MULTIPLE_RENDER_TARGETS];


	/** Initialise object (find suitable depth and stencil format).
        Must be called every time the bindings change.
        It fails with an exception (ERR_INVALIDPARAMS) if:
        - Attachment point 0 has no binding
        - Not all bound surfaces have the same size
        - Not all bound surfaces have the same internal format
    */
    void initialise();
};


U2EG_NAMESPACE_END


#endif
